package file_info

import (
	"errors"
	"path/filepath"
	"sync"
)

const (
	NormalAction Tag = iota
	OnlyDelete
	SkipOperation

	unknown
)

type Tag int

type FileInfo struct {
	fileAbsPath string
	hash        string
	tag         Tag
	fileStat    *fileStat
	rwLock      *sync.RWMutex
}

func NewFileInfo(filePath, hash string) (*FileInfo, error) {
	fileAbsPath, err := filepath.Abs(filePath)
	if err != nil {
		return nil, err
	}
	s, err := stat(fileAbsPath)
	if err != nil {
		return nil, err
	}
	return &FileInfo{
		fileAbsPath: fileAbsPath,
		hash:        hash,
		tag:         NormalAction,
		fileStat:    s,
		rwLock:      new(sync.RWMutex),
	}, nil
}

func (f *FileInfo) RefreshStat() error {
	f.rwLock.Lock()
	defer f.rwLock.Unlock()
	s, err := stat(f.fileAbsPath)
	if err != nil {
		return err
	}
	f.fileStat = s
	return nil
}

func (f *FileInfo) Path() string {
	return f.fileAbsPath
}

func (f *FileInfo) Hash() string {
	return f.hash
}

func (f *FileInfo) Size() int64 {
	f.rwLock.RLock()
	defer f.rwLock.RUnlock()
	return f.fileStat.size()
}

func (f *FileInfo) DevNum() uint64 {
	return uint64(f.fileStat.devNum())
}

func (f *FileInfo) SetHash(hash string) {
	f.hash = hash
}

func (f *FileInfo) SetTag(tag Tag) error {
	if tag < NormalAction || tag >= unknown {
		return errors.New("unknown tag")
	}
	f.tag = tag
	return nil
}

func (f *FileInfo) GetTag() Tag {
	return f.tag
}

func (f *FileInfo) GetStat() *fileStat {
	f.rwLock.RLock()
	defer f.rwLock.RUnlock()
	return f.fileStat
}

func (f *FileInfo) Copy() *FileInfo {
	f.rwLock.RLock()
	defer f.rwLock.RUnlock()
	return &FileInfo{
		fileAbsPath: f.fileAbsPath,
		hash:        f.hash,
		tag:         f.tag,
		fileStat:    f.fileStat,
		rwLock:      new(sync.RWMutex),
	}
}

func (f *FileInfo) IsSameFile(target *FileInfo) bool {
	f.rwLock.RLock()
	target.rwLock.RLock()
	defer f.rwLock.RUnlock()
	defer target.rwLock.RUnlock()
	return sameFile(f.fileStat, target.fileStat)
}

func (f *FileInfo) Release() {
	f.rwLock.Lock()
	defer f.rwLock.Unlock()
	f.fileAbsPath = ""
	f.hash = ""
	f.tag = unknown
	f.fileStat = nil
	f.rwLock = nil
}
